package com.medi.framework.aspectj;

import com.medi.business.domain.DataCondition;
import com.medi.business.domain.DataInterface;
import com.medi.business.domain.DataRelation;
import com.medi.business.mapper.DataConditionMapper;
import com.medi.business.mapper.DataInterfaceMapper;
import com.medi.business.mapper.DataRelationMapper;
import com.medi.common.annotation.CustomScope;
import com.medi.common.core.domain.BaseEntity;
import com.medi.common.core.domain.entity.SysUser;
import com.medi.common.core.domain.model.LoginUser;
import com.medi.common.core.domain.model.vo.UserInfoVo;
import com.medi.common.core.redis.RedisCache;
import com.medi.common.utils.SecurityUtils;
import com.medi.common.utils.StringUtils;
import com.medi.framework.security.context.PermissionContextHolder;
import org.apache.commons.lang3.ObjectUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 数据过滤处理
 *
 * @author medi
 */
@Aspect
@Component
public class CustomScopeAspect {

    /**
     * 数据权限过滤关键字
     */
    public static final String DATA_SCOPE = "dataScope";

    @Autowired
    DataInterfaceMapper dataInterfaceMapper;

    @Autowired
    DataRelationMapper dataRelationMapper;

    @Autowired
    DataConditionMapper dataConditionMapper;

    @Autowired
    private RedisCache redisCache;

    @Before("@annotation(controllerDataScope)")
    public void doBefore(JoinPoint point, CustomScope controllerDataScope) throws Throwable {
        clearDataScope(point);
        handleDataScope(point, controllerDataScope);
    }

    protected void handleDataScope(final JoinPoint joinPoint, CustomScope controllerDataScope) {
        // 获取当前的用户
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (StringUtils.isNotNull(loginUser)) {
            SysUser currentUser = loginUser.getUser();
            UserInfoVo userInfo = loginUser.getUserInfo();
            // 如果是超级管理员，则不过滤数据
            if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) {
                String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext());
                dataScopeFilter(joinPoint, currentUser, userInfo, controllerDataScope.tableAlias(), controllerDataScope.userAlias(), permission);
            }
        }
    }

    /**
     * 数据范围过滤
     *
     * @param joinPoint    切点
     * @param user         系统用户
     * @param userInfo     客户信息
     * @param tableAlias 公司别名
     * @param userAlias    用户别名
     * @param permission   权限字符
     */
    public void dataScopeFilter(JoinPoint joinPoint, SysUser user, UserInfoVo userInfo, String tableAlias,String userAlias, String permission) {
        StringBuffer sqlString = new StringBuffer();
        List<String> conditions = new ArrayList<String>();
        if (ObjectUtils.isEmpty(user) || ObjectUtils.isEmpty(userInfo)) {
            return;
        }
        String pointName = joinPoint.getTarget().getClass().getName();
        List<DataInterface> dataInterfaceList = dataInterfaceMapper.selectDataInterfaceListByName(pointName);
        if (ObjectUtils.isEmpty(dataInterfaceList) || dataInterfaceList.size() <= 0) {
            return;
        }
        DataInterface dataInterface = dataInterfaceList.get(0);
        if (ObjectUtils.isEmpty(dataInterface)) {
            return;
        }
        String infId = dataInterface.getId();
        List<DataRelation> dataRelationList = dataRelationMapper.selectDataRelationListByInfId(infId);
        if (ObjectUtils.isEmpty(dataRelationList) || dataRelationList.size() <= 0) {
            return;
        }
        dataRelationList = dataRelationList.stream().filter(o -> o.getObjectId().equals(userInfo.getId())
                || userInfo.getRoleIds().contains(o.getObjectId())).collect(Collectors.toList());
        if (ObjectUtils.isEmpty(dataRelationList) || dataRelationList.size() <= 0) {
            return;
        }

        for (DataRelation dataRelation : dataRelationList
        ) {
            if (StringUtils.isNotBlank(sqlString)) {
                sqlString.append(" OR ");
            }
            sqlString.append(" ( ");
            String strSql = "";
            List<DataCondition> dataConditionList = dataConditionMapper.selectDataConditionListByDataRelationId(dataRelation.getId());
            if (ObjectUtils.isEmpty(dataConditionList) || dataConditionList.size() <= 0) {
                continue;
            }
            if (!StringUtils.isNotBlank(dataRelation.getFormula())) {
                String strFormula = dataRelation.getFormula();
                strSql = strFormula;
                for (int i = 1; i < dataConditionList.size() + 1; i++) {
                    strSql = strSql.replace("" + i, "{@$$$" + i + "$$$@}");
                }
            } else {
                for (int i = 1; i < dataConditionList.size() + 1; i++) {
                    if (strSql != "") {
                        strSql += " AND ";
                    }
                    strSql += " {@$$$" + i + "$$$@} ";
                }
            }
            int num = 1;
            for (DataCondition dataCondition : dataConditionList) {
                String clName = dataCondition.getField();
                if(StringUtils.isNotBlank(tableAlias))
                {
                    clName = tableAlias + "." + clName;
                }
                String stone = " " + clName;
                String value = getValue(userInfo, dataCondition.getValueType(), dataCondition.getValueExl());
                switch (dataCondition.getSymbolId()) {
                    case 1:// 等于
                        stone += " = " + value;
                        break;
                    case 2:// 大于
                        stone += " > " + value;
                        break;
                    case 3:// 大于等于
                        stone += " >= " + value;
                        break;
                    case 4:// 小于
                        stone += " < " + value;
                        break;
                    case 5:// 小于等于
                        stone += " <= " + value;
                        break;
                    case 6:// 包含
                        stone += StringUtils.format(" like concat('%', '{}', '%') ", value);
                        break;
                    case 7:// 包含于
                        String[] values = value.split(",");
                        if (values.length > 0) {
                            stone += " in (";
                            for (String str : values) {
                                stone += StringUtils.format("{},", str);
                            }
                            stone = stone.substring(0, stone.length() - 1);
                            stone = stone + ")";
                        }
                        break;
                    case 71:// CHARINDEX于
                        stone = stone.replace(clName, "");
                        stone += StringUtils.format(" LOCATE('{}'," + clName + ") > 0", value);
                        break;
                    case 8:// 不等于
                        stone += " != " + value;
                        break;
                    case 9:// 不包含
                        stone += StringUtils.format("not like concat('%', '{}', '%') ", value);
                        ;
                        break;
                    case 10:// 不包含于
                        values = value.split(",");
                        if (values.length > 0) {
                            stone += "not in (";
                            for (String str : values) {
                                stone += StringUtils.format("{},", str);
                            }
                            stone = stone.substring(0, stone.length() - 1);
                            stone = stone + ")";
                        }
                        break;
                    default:
                        break;
                }
                stone += " ";
                strSql = strSql.replace("{@$$$" + num + "$$$@}", stone);
                num++;
            }

            sqlString.append(strSql);
            sqlString.append(" ) ");
        }
        Object params = joinPoint.getArgs()[0];
        if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {
            BaseEntity baseEntity = (BaseEntity) params;
            if(StringUtils.isBlank(permission))
            {
                baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
            }
            else
            {
                baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ") AND (" + permission + ")");
            }

        }
    }

    /**
     * 数据范围过滤
     *
     * @param type  切点
     * @param value 系统用户
     */
    private String getValue(UserInfoVo userInfo, Integer type, String value) {
        /**字段值类型1.文本2.登录者ID3.登录者账号4.登录者公司5.登录者部门6.登录者岗位7.登录者角色8.部门所在人员9.公司所在人员10.岗位所在人员11.角色所在人员12.登录者所在人员*/
        String text = "";
        switch (type) {
            case 1:// 文本
                text = value;
                break;
            case 2:// 登录者ID
                text = userInfo.getId();
                break;
            case 3:// 登录者公司
                text = userInfo.getCompanyId();
                break;
            case 4:// 登录者公司及下属公司
                for (String id : userInfo.getCompanyIds()) {
                    if (text != "") {
                        text += ",";
                    }
                    text += id;
                }
                break;
            case 5:// 登录者部门
                text = userInfo.getOrgId();
                break;
            case 51:// 登录者部门及下属部门
                for (String id : userInfo.getOrgIds()) {
                    if (text != "") {
                        text += ",";
                    }
                    text += id;
                }
                break;

            case 6:// 登录者公司及下属公司(不含商户)
                for (String id : userInfo.getCompanyIdListSys()) {
                    if (text != "") {
                        text += ",";
                    }
                    text += id;
                }
                break;
            case 7:// 指定负责人下的商户
                for (String id : userInfo.getCompanyIdListTenant()) {
                    if (text != "") {
                        text += ",";
                    }
                    text += id;
                }
                break;
//            case 6:// 登录者岗位
//                text = userInfo.postIds;
//                break;
            case 8:// 登录者角色
                text = userInfo.getRoleIds();
                break;
            case 9:// 登录者分区
                text = userInfo.getAreaIds();
                break;
//            case 9:// 登录者分局
//                text = userInfo.geto;
//                break;
//            case 10:// 登录者管理的企业
//                text = userInfo.customerIds;
//                break;
            default:
                text = value;
                break;
        }
        return text;
    }

    /**
     * 拼接权限sql前先清空params.dataScope参数防止注入
     */
    private void clearDataScope(final JoinPoint joinPoint) {
        Object params = joinPoint.getArgs()[0];
        if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {
            BaseEntity baseEntity = (BaseEntity) params;
            baseEntity.getParams().put(DATA_SCOPE, "");
        }
    }
}
